#ifndef VARTABLE_H
#define VARTABLE_H
#include "Value.h"
#include <string>
#include <cassert>
//#include <iostream>  // for clog
class VarTable
{
	static const long size = 1000003;//1000003, 10000019, 100000007
	class node
	{
	public:
		std::string id;
		Value* pvar;
		node* next;
		node(const std::string& Id, Value* Pvar, node* Next = NULL): id(Id), pvar(Pvar), next(Next) {}
		~node()
		{
			delete pvar;// reference(count) or a value with two name are not supported
			pvar = NULL;
			delete next;
			next = NULL;
		}
	};
	node* table[size];
	long BKRDHash(const std::string& s) const;
	node* find(const std::string& s) const;
	static VarTable* instance;
	VarTable();
	VarTable(const VarTable&);
public:
	static void init()
	{
		assert(instance == NULL);
		instance = new VarTable();
	}
	static VarTable* getInstance()
	{
		assert(instance != NULL);
		return instance;
	}
	static void del()
	{
		delete instance;
		instance = NULL;
	}
	~VarTable();
	ValueInt* get(const std::string& s) const
	{
		node* p = find(extractVarname(s));
		if (p == NULL)
			return NULL;
		else
			return (ValueInt*)(p -> pvar);
	}
	void def(const std::string& s, const ValueInt& Pvar) // called only when 'get' returns NULL
	{
		//std::clog << "LOG: Defining \"" << extractVarname(s) << "\"" << std::endl;
		ValueInt* pvar = new ValueInt();
		pvar -> assign(Pvar);
		long hash = BKRDHash(extractVarname(s));
		table[hash] = new node(extractVarname(s), pvar, table[hash]);
	}
	std::string extractVarname(const std::string& rawname) const;
};
#endif

